import { IModalEmit, IModalRef, RenderModal } from '@inbiz/render';
import { useInbizData, queryData, customRequest } from '@inbiz/hooks';
import { InbizIcon, useEvents } from '@inbiz/utils';
import {
  forwardRef,
  Ref,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import { Menu, Item, useContextMenu } from 'react-contexify';
import 'react-contexify/dist/ReactContexify.css';
import { Tree as AntdTree, Modal, message, Input, Empty, Button, TreeNodeProps } from 'antd';
import { delTreeData, getTreeDatas, queryTreeParentIdDatas } from '../../services';
import api from '../../api';
import type { IProps } from '../../index';
import { Oparetion } from '../../types';
import { hasAuth } from '@inbiz/basic/AuthForm';
import SearchList from './SearchList';
import './style.less';
import { PlusOutlined } from '@ant-design/icons';
import { TextWidget, getMessage } from '@inbiz/react';
import {
  formatTreeData,
  getFieldKey,
  updateTreeData,
  findTreeNode,
  findTreeNodes,
  findTreeParents,
  ITreeData,
  treeDataToArray,
  treeDataLevelFormat,
} from '../../utils';
import { EventDataNode } from 'antd/es/tree';

type IRef = Ref<ReturnType<typeof api>>;
const Tree = forwardRef((props: IProps, ref: IRef) => {
  const {
    showIcon,
    checkable,
    prefixCls = 'inbiz-Tree',
    config,
    inbiz,
    callBackEvents,
    businessData,
    sourceModel,
    sourcetype = 'model',
    selectedKeys = [],
    value,
    expandNode,
    emit,
    title,
    minWidth,
    maxWidth,
    minHeight,
    maxHeight,
    disabled,
    readOnly,
    viewMode,
    placeholder,
    search,
    draggable,
    checkStrictly,
    unSelected,
    searchPosition = 'right',
    searchIcon = { color: '#aaa', type: 'icon-sousuo' },
    ...otherProps
  } = props;

  // 静态数据
  const { operations, IconsSettings, fieldRelation, appId, rootId, sourceTypeNum } = useMemo(() => {
    const { operations, IconsSettings, fieldRelation } = config;
    return {
      sourceTypeNum: 1 as const,
      operations,
      IconsSettings,
      fieldRelation,
      rootId: fieldRelation?.rootId || '0',
      appId: inbiz.appInfo.appId,
    };
  }, [config]);

  // 所有回调事件的集合
  const [configEvents] = useEvents(callBackEvents, props.emit);
  // treeData的最新数据，只用于数据查找，不参与任何业务逻辑
  const treeDataRef = useRef<ITreeData>();
  // treeData的数组平铺结构， 只用于搜索
  const treeListRef = useRef<ITreeData>();
  const modalRef = useRef<IModalRef>();

  const {
    loading,
    data: treeData,
    mutate: $treeData,
    runAsync,
  } = useInbizData(
    () => {
      if (sourcetype === 'model') {
        return {
          service: ({
            appId,
            ...other
          }: {
            appId: string;
            sourceKey: string;
            value?: string | number;
            parentId?: string | number;
            sourceType: 1;
            id?: string | number;
          }) => {
            return other?.sourceKey ? getTreeDatas(appId, other) : Promise.resolve([]);
          },
        };
      } else {
        if (typeof sourceModel === 'object') {
          return sourceModel;
        } else {
          return { modelkey: sourceModel! };
        }
      }
    },
    {
      formatResult: ({
        data,
        lastData,
        params,
      }: {
        data: { Data: any[]; Rows?: [] };
        lastData: ITreeData;
        params: { key?: string };
      }): ITreeData => {
        if (!lastData?.length) {
          return formatTreeData({
            data: data.Data || data.Rows,
            key: treeShowNodeId,
            title: showTreeNameKey,
            childrenKey: 'child',
            treeNodeId: [treeNodeId, treeShowNodeId],
            treeNodeParentId: [treeNodeParentId, treeShowNodeParentId],
            format: (data) => {
              data.key = data?.key?.toString();
            },
          }) as ITreeData;
        } else {
          let childData =
            (sourcetype === 'model'
              ? data.Data?.[0]?.child
              : Array.isArray(data.Rows)
                ? data.Rows
                : [data.Rows]) || [];
          let keyValue = params.key as string;
          // // 添加到顶级节点时额外处理
          // if (
          //   childData?.length === 0 &&
          //   data?.Data?.[0]?.[treeNodeParentId] == rootId &&
          //   data?.Data?.[0]?.[treeNodeId] != params.key &&
          //   sourcetype === 'model'
          // ) {
          //   keyValue = rootId;
          //   childData = data.Data || [];
          // }

          const tree = formatTreeData({
            data: childData,
            key: treeShowNodeId,
            title: showTreeNameKey,
            childrenKey: 'child',
            treeNodeId: [treeNodeId, treeShowNodeId],
            treeNodeParentId: [treeNodeParentId, treeShowNodeParentId],
            format: (data) => {
              data.key = data?.key?.toString();
            },
          });
          return updateTreeData({
            type: 'add',
            keyValue,
            treeData: lastData,
            data: tree!,
            // isRoot: data.Data?.[0]?.[treeNodeParentId] == rootId,
          });
        }
      },
      initialData: [],
      configEvents,
    },
  );
  // 保存最新数据的应用， 用于查询, 不参加任何业务逻辑
  useEffect(() => {
    treeDataRef.current = treeData;
    treeListRef.current = treeDataToArray(treeData);
  }, [treeData]);

  // 显示字段配置
  const [
    treeNameKey, // 显示字段
    showTreeNameKey,
    treeNodeId, // 选中字段
    treeShowNodeId,
    treeNodeParentId, // 父级字段
    treeShowNodeParentId,
  ] = useMemo(() => {
    return [
      getFieldKey(fieldRelation['label']),
      getFieldKey(fieldRelation['label'], 1),
      getFieldKey(fieldRelation['id']),
      getFieldKey(fieldRelation['id'], 1),
      getFieldKey(fieldRelation['parentId']),
      getFieldKey(fieldRelation['parentId'], 1),
    ];
  }, [fieldRelation]);
  // 选中的key
  const [currentKey, $currentKey] = useState<string[]>(selectedKeys);
  // 展开的key
  const [expandedKeys, $expandedKeys] = useState<string[]>([]);

  // 搜索相关
  const [searchKey, $searchKey] = useState('');
  const [searchList, $searchList] = useState([]);
  const [showSearch, $showSearch] = useState(false);
  // 多选的key
  const [checkedKeys, $checkedKeys] = useState<{ checked: string[]; halfChecked: string[] }>({
    checked: [],
    halfChecked: [],
  });
  const setCheckedKeys = useCallback(
    (key: string | string[] | object, isChecked?: boolean) => {
      if (typeof key === 'object') {
        if (Array.isArray(key)) {
          $checkedKeys({
            checked: key,
            halfChecked: [],
          });
        } else {
          $checkedKeys(key as typeof checkedKeys);
        }
      } else {
        $checkedKeys((data) => {
          let newChecked = [...data.checked];
          if (isChecked) {
            newChecked.push(key);
          } else {
            newChecked = newChecked.filter((item) => item != key);
          }
          return {
            ...data,
            checked: newChecked,
          };
        });
      }
    },
    [checkStrictly],
  );

  // 选中节点的数据
  const selectedNode = useMemo(() => {
    if (!treeDataRef.current || !treeDataRef.current?.length) {
      // 第一次不执行事件
      return [];
    }
    if (currentKey?.length) {
      const node = findTreeNode({ treeData: treeDataRef.current, keyValue: currentKey[0] })!;
      if (node) {
        emit?.('onSelect', [node.key?.toString()], node);
      }
      return [node];
    } else {
      emit?.('onSelect', [], undefined);
      return [];
    }
  }, [currentKey, emit]);

  // 是否有权限
  const hasPerm = useMemo(() => {
    let flag = false;
    //@ts-ignore
    const authArr = props.inbiz?.auth || [];
    if (authArr.length == 0) {
      flag = true;
    } else {
      const hasPermList = authArr.filter((item: any) => item.IsHavePerm);
      flag = hasPermList.length ? true : false;
    }
    return flag;
    //@ts-ignore
  }, [props.inbiz?.auth]);

  // 请求数据的公共方法
  const getData = async (params: { key: string }) => {
    if (!sourceModel && !configEvents.current.onRequest) {
      return;
    }
    let data = {};
    if (sourcetype === 'model') {
      data = {
        sourceKey: sourceModel!,
        sourceType: sourceTypeNum,
        id: treeNodeId,
        parentId: treeNodeParentId,
        key: params.key,
        appId,
      };
    } else {
      if (typeof sourceModel === 'string') {
        data = {
          appId,
          key: sourceModel,
          iConditions: params,
        };
      } else {
        data = params;
      }
    }
    return runAsync(data).then(
      (res: any) => {
        emit?.('onSuccess', res);
      },
      (error: any) => {
        emit?.('onError', error);
      },
    );
  };

  // 加载数据
  const lazyLoadTreeData = async (node: EventDataNode<{ children?: ITreeData; key: string }>) => {
    if (!node.children) {
      return getData(node);
    }
  };

  // 操作关联组件
  const relationOpt = useCallback(
    (id?: string | number | null) => {
      const _id = id || currentKey[0];
      if (props.inbiz !== undefined) {
        if (props.selectComponent && props.relationField) {
          const { selectComponent } = props as unknown as { selectComponent: string };
          const data =
            _id !== undefined
              ? {
                id: selectComponent,
                query: [
                  {
                    connector: 'and',
                    field: props.relationField?.split('@')[1] || props.relationField,
                    value: _id,
                    modelName: props.relationField?.includes('@')
                      ? props.relationField?.split('@')[0]
                      : '',
                    operator: 'like',
                  },
                ],
                queryData: {
                  [(props.relationField?.split('@')[1] || props.relationField) as string]: id,
                },
              }
              : {
                id: selectComponent,
                query: [],
                queryData: {},
              };
          const result = configEvents.current.onBeforeRelation?.(data, selectedNode) ?? true;
          if (result) {
            const resultData = typeof result == 'object' ? result : data;
            if (props.inbiz(selectComponent)?.setParams) {
              props.inbiz(selectComponent)?.setParams(resultData.query);
              props.inbiz(selectComponent)?.setPageInfo(resultData.queryData);
              props.inbiz(selectComponent)?.load();
            }
          }
        }
      }
    },
    [props.selectComponent, props.relationField, selectedNode, fieldRelation],
  );

  useEffect(() => {
    // 首次加載
    getData({ key: rootId }).then(() => {
      emit?.('onload');
      if (fieldRelation?.selectedId) {
        setTimeout(function () {
          setSelectNode(fieldRelation.selectedId!.split(','));
        }, 0);
      }
      relationOpt(fieldRelation?.selectedId);
      // 默认展开
      setTimeout(() => {
        const key = treeDataRef.current?.[0]?.key;
        if (expandNode && (!fieldRelation?.selectedId || key == fieldRelation?.selectedId)) {
          if (key) {
            $expandedKeys([key]);
          }
        }
      }, 100);
    });
  }, [sourceModel?.['url'] ?? sourceModel]);

  // 树形组件重载刷新方法
  const onRefresh=(key?:string)=>{
    $treeData([])
    getData({key})
  }

  // 根据key选中节点,为模型数据时, 可以自动加载不存在的节点
  const setSelectNode = useCallback(
    async (keys: string | string[], isSelect: boolean = true) => {
      // 查找所有父级节点
      const setExpanded = (key: string, parentNode?: ITreeData) => {
        const parents =
          parentNode ??
          findTreeParents({ treeData: treeDataRef.current, keyValue: key, resultSelf: true });
        if (parents?.length) {
          const node = parents.pop();
          // 找到所有节点，展开并选中
          $expandedKeys((keys) => {
            const pKeys = parents.map((item) => item.key);
            return [...new Set([...keys, ...pKeys])];
          });
          if (isSelect) {
            if (checkable) {
              $checkedKeys((old) => ({
                checked: [...(old.checked || []), node?.key!],
                halfChecked: [],
              }));
            } else {
              $currentKey([node?.key!]);
            }
          }
        }
      };
      const notKey = [];
      const dataKeys = Array.isArray(keys) ? keys : [keys];
      for (const key of dataKeys) {
        const parents = findTreeParents({
          treeData: treeDataRef.current,
          keyValue: key,
          resultSelf: true,
        });
        if (parents?.length) {
          setExpanded(key, parents);
        } else {
          notKey.push(key);
        }
      }
      if (notKey?.length) {
        if (sourcetype == 'model') {
          await loadOriginData(notKey);
          notKey.forEach((key) => {
            setExpanded(key);
          });
        } else {
          // 自定义数据源不做处理
        }
      }
    },
    [fieldRelation, sourceModel, emit, checkable],
  );

  // 加载远端数据, 暂时只支持模型数据
  const loadOriginData = useCallback(
    async (key: string | string[]) => {
      if (sourcetype == 'model') {
        const pathArr: { path: string }[] = await queryTreeParentIdDatas(appId, {
          sourceKey: sourceModel!,
          sourceType: sourceTypeNum,
          id: treeNodeId,
          parentId: treeNodeParentId,
          values: Array.isArray(key) ? key.join(',') : key,
        });
        if (!pathArr?.length) {
          return Promise.reject('不存在远端数据');
        }
        for (const { path } of pathArr) {
          if (!path) {
            return Promise.reject('不存在远端数据');
          }
          // 最后一个节点不需要额外请求在上一个节点的child中
          const treeKeys = path.includes('/') ? (path.split('/').slice(0, -1) as string[]) : [path];
          // 在本地存在的节点,最后一个链条的节点
          const thereNode = findTreeNodes({ treeData: treeDataRef.current, keyValue: treeKeys })
            .reverse()
            .find((item) => !!item);
          // 添加到根节点， 没有节点数据， 或者父节点存在时添加
          if (thereNode || !treeDataRef.current?.length || !path.includes('/')) {
            const index = thereNode ? treeKeys.findIndex((item) => item == thereNode.key) : 0;
            const loadKeys = treeKeys.slice(index);

            for (let i = 0, len = loadKeys.length; i < len; i++) {
              const key = loadKeys[i];
              const nextKey = loadKeys[i + 1];

              const node = nextKey
                ? findTreeNode({ treeData: treeDataRef.current, keyValue: nextKey })
                : false;
              if (!node) {
                await getData({ key });
              }
              await new Promise((resolve) => setTimeout(resolve, 10));
            }
          } else {
            return Promise.reject('为找到树结构中的key');
          }
        }
        return true;
      } else {
        return Promise.reject('自动定义数据源，不支持自动加载远端数据');
      }
    },
    [fieldRelation, sourceModel],
  );

  // 搜索字清空 搜索结果列表清空
  useEffect(() => {
    if (!searchKey) {
      $showSearch(false);
    }
  }, [searchKey]);

  const options = useMemo(() => {
    if (disabled || readOnly || !operations?.length || viewMode == 'look') {
      return [];
    } else {
      return operations.map((item: Oparetion) => {
        let oneOparetion: Oparetion = {};
        oneOparetion.name = item.name;
        oneOparetion.type = item.type;
        const page = item.page;
        if (item.type === 'delete') {
          oneOparetion.hander = async (nodeData: any) => {
            const id = nodeData.key;
            emit?.('onClick', { event: item.type, node: nodeData });
            let isContinue = true;
            if (configEvents?.current?.onBeforeOperationAsync) {
              isContinue = await configEvents?.current?.onBeforeOperationAsync(item.type, {
                ...nodeData,
                [treeNodeId]: id,
              });
            }
            if (!isContinue) {
              return;
            }
            Modal.confirm({
              title: getMessage('Tree.warning'),
              content: getMessage('Tree.areYouSureToDeleteThisTreeNode'),
              okText: getMessage('Tree.determine'),
              cancelText: getMessage('Tree.cancel'),
              onOk: async () => {
                if (typeof sourceModel === 'string') {
                  const delres = await delTreeData(appId, {
                    sourceType: sourceTypeNum,
                    sourceKey: sourceModel,
                    //@ts-ignore
                    name: props.modelname,
                    id: treeNodeId,
                    parentId: treeNodeParentId,
                    value: id,
                  });
                  if (!delres || (typeof delres === 'object'&& delres.result == 1)) {
                    let msg = getMessage('Tree.nodeDeletionFailed')
                    if (typeof delres === 'object') {
                      msg = getMessage('global.' + delres.message.replace(':', ''));
                      if (msg.indexOf('global.') === 0) {
                        msg = delres.message
                      }
                    }
                    message.error(msg);
                    return;
                  }
                } else {
                  if (item.api) {
                    const request = customRequest(item.api as any, props.inbiz);
                    if (item.api['url']) {
                      await request(nodeData);
                    } else {
                      await request({ iConditions: nodeData });
                    }
                  } else {
                    return;
                  }
                }
                emit?.('onDelete', nodeData);
                $treeData((origin?: ITreeData) => {
                  return updateTreeData({
                    treeData: origin,
                    keyValue: id as string,
                    type: 'delete',
                  });
                });
              },
            });
          };
        } else {
          const [pageName, pageId] = page ? page.split(',') : [];
          oneOparetion.hander = async (nodeData: { id: any }) => {
            emit?.('onClick', { event: item.type, node: nodeData });
            if (!pageId) {
              message.warning(getMessage('TreeView.pleaseBindThePage'));
              return;
            }
            const queryData: any = {};
            const { id } = nodeData;

            if (item.type === 'add') {
              queryData[treeNodeParentId] = id;
            } else {
              queryData['id'] = id;
            }
            let isContinue = true;
            if (configEvents?.current?.onBeforeOperationAsync) {
              isContinue = await configEvents?.current?.onBeforeOperationAsync(item.type, {
                ...nodeData,
                [treeNodeId]: id,
              });
            }
            if (!isContinue) {
              return;
            }
            const openOpt = {
              data: { ...nodeData, nodeId: id },
              queryData: queryData,
              pageId,
              id: pageName,
            };
            //@ts-ignore
            modalRef?.current?.onOpen(
              openOpt,
              item.type == 'add' ? getMessage('Tree.addTo') : getMessage('Tree.edit'),
            );
          };
        }
        return oneOparetion;
      });
    }
  }, [operations, readOnly, viewMode, disabled, sourceModel]);

  // 当配置了图标后，准备图标相关的逻辑
  const IconsSettingsObj = useMemo(() => {
    // const data = {};
    let data: any = {}
    IconsSettings.config?.forEach((item: any) => {
      if (item.iconTypeKey) {
        //@ts-ignore
        const field = IconsSettings.field;
        data[item.iconTypeKey] = item.defaultIcon;
        data[`${item.iconTypeKey}_expand`] = item.expandIcon;
        data['type'] = 'node';
        data['field'] = field.indexOf('$') !== -1 ? field?.split('$')[1] : field;
      } else {
        data[item.iconType] = item.iconImg;
        data['type'] = 'normal';
      }
    });
    return data;
  }, [IconsSettings?.config]);

  const renderIcon = useCallback(
    (nodeData: TreeNodeProps) => {
      const { data } = nodeData;
      const level = data._level + 1;
      let iconType = undefined;
      if (IconsSettingsObj['type'] == 'normal') {
        iconType =
          level == 1
            ? IconsSettingsObj['topIcon']
              ? IconsSettingsObj['topIcon']
              : nodeData.expanded
                ? IconsSettingsObj['expandIcon']
                  ? IconsSettingsObj['expandIcon']
                  : IconsSettingsObj['defaultIcon']
                : IconsSettingsObj['defaultIcon']
            : nodeData.expanded
              ? IconsSettingsObj['expandIcon']
                ? IconsSettingsObj['expandIcon']
                : IconsSettingsObj['defaultIcon']
              : IconsSettingsObj['defaultIcon'];
      } else {
        iconType = nodeData.expanded
          ? IconsSettingsObj[`${data[IconsSettingsObj['field']]}_expand`]
          : IconsSettingsObj[data[IconsSettingsObj['field']]];
      }
      return iconType?.type ? (
        <InbizIcon type={iconType?.type} style={{ color: iconType.color }}></InbizIcon>
      ) : (
        <InbizIcon type={iconType}></InbizIcon>
      );
    },
    [IconsSettingsObj],
  );

  const onExpand = useCallback((newExpandedKeys: string[], node: any): void => {
    /**
     *
     * 新增数据后，点击收起，实际上会在newExpandedKeys里面再次添加一次对应的节点，
     * 所以需要多次点击才能实际收起
     */
    const nextExpandedKeys = newExpandedKeys.filter(
      (ele: string, _: any, self: string[]) => self.indexOf(ele) === self.lastIndexOf(ele),
    );
    $expandedKeys(nextExpandedKeys);
    emit?.('onExpand', node);
  }, []);

  const handleSelect = useCallback(
    (key, e): void => {
      emit?.('onNodeClick', e.node);
      if (unSelected && !checkable) {
        if (e.selected) {
          $currentKey(key);
          relationOpt(key[0]);
        }
      } else {
        $currentKey(key);
        relationOpt(key[0]);
      }
      // 多选时勾选多选框
      if (checkable) {
        if (checkStrictly) {
          $checkedKeys((origin) => {
            const { checked } = origin;
            const newChecked = [...checked];
            const index = newChecked.findIndex((item) => item == e.node.key);
            if (index == -1) {
              // 不存在是添加
              newChecked.push(e.node.key);
            } else {
              // 存在时删除
              newChecked.splice(index, 1);
            }
            setTimeout(() => {
              emit?.(
                'onCheck',
                checkStrictly
                  ? newChecked
                  : {
                    ...origin,
                    checked: newChecked,
                  },
                e.node,
              );
            }, 0);
            return {
              ...origin,
              checked: newChecked,
            };
          });
        }
      }
    },
    [checkable, checkStrictly, unSelected],
  );
  const modalEmit: IModalEmit = useCallback(
    (type: string, ...arg: Array<any>): void => {
      // 模型接口才支持， 修改数据
      if (sourcetype != 'model') {
        return;
      }
      const [dataId, node] = arg;
      if ((type === 'onAdd' || type === 'onEdit') && node) {
        // 保存或新增后更新list
        queryData({
          appId: props.inbiz.appInfo.appId,
          key: props.sourceModel!,
          pageInfo: {
            index: 1,
            size: 999,
          },
        }).then(async (res) => {
          if (res['Success'] === 0) {
            let nodeId: string = '',
              parentId: any;
            const resNode = res.Rows?.find((item) => {
              if (item.id == dataId.data) {
                nodeId = item[treeShowNodeId] as string;
                parentId = item[treeShowNodeParentId];
                return true;
              } else {
                return false;
              }
            });
            const { id } = node;
            // 如果返回来的 nodeId 跟 节点的最后一位一致，表示是已存在的节点
            if (dataId.data == id && parentId != 0 && parentId != null) {
              if (node?.[treeShowNodeParentId] != parentId) {
                $treeData((origin: any) => {
                  return updateTreeData({ treeData: origin, type: 'delete', keyValue: node?.key! });
                });
              }
            } else {
              if (
                type == 'onEdit' &&
                node?.[treeShowNodeParentId] &&
                node?.[treeShowNodeParentId] != 0
              ) {
                $treeData((origin: any) => {
                  return updateTreeData({ treeData: origin, type: 'delete', keyValue: node?.key! });
                });
              }
            }
            if (type === 'onAdd' || type === 'onEdit') {
              const treeNode = formatTreeData({
                data: [resNode!],
                key: treeShowNodeId,
                title: showTreeNameKey,
                childrenKey: 'child',
                treeNodeId: [treeNodeId, treeShowNodeId],
                treeNodeParentId: [treeNodeParentId, treeShowNodeParentId],
                format: (data) => {
                  data.key = data?.key?.toString();
                },
              })?.[0];

              $treeData((treeData: any) => {
                if (!treeData?.length) {
                  return [treeNode] as ITreeData;
                }
                return updateTreeData({
                  treeData,
                  //@ts-ignore
                  type: type === 'onAdd' ? 'add' : 'update',
                  keyValue: type === 'onAdd' ? parentId : nodeId,
                  data: treeNode!,
                  isRoot:
                    !treeNode?.[treeNodeParentId] ||
                    treeNode?.[treeNodeParentId] == '0' ||
                    treeNode?.[treeNodeParentId] == rootId,
                });
              });
              if (type === 'onAdd' && nodeId !== undefined) {
                $currentKey([
                  typeof nodeId === 'string' ? nodeId : (nodeId as Number).toString?.(),
                ]);
                $expandedKeys((keys) => {
                  return [...new Set([...keys, parentId?.toString?.()])];
                });
              }
            }
          }
        });
      }
      props.emit?.(type, ...arg);
    },
    [props.emit, sourcetype, fieldRelation],
  );

  const changeString = (str?: string) => {
    let result = '';
    if (str == 'Tree.add') {
      result = 'Tree.addTo'
    } else if (str == 'Tree.edit') {
      result = 'Tree.edit'
    } else if (str == 'Tree.delete') {
      result = 'Tree.delete'
    }
    return result || str;
  }

  const menuData = useMemo(() => {
    let newOptions = treeData?.length ? options : options.filter((item) => item.type == 'add');
    let items = newOptions.map((item) => {
      const tmpName = changeString(item.name);

      return {
        key: tmpName,
        name: tmpName,
        originName: item.name,
        handler: ({ props }: { props: object }) => {
          item.hander?.(props);
        },
      };
    });
    return {
      menuId: props.controlId,
      items: items,
    };
  }, [treeData]);

  const { show } = useContextMenu({
    id: menuData.menuId,
  });
  // 空数据时的添加按钮
  const addButton = useMemo(() => {
    const { operations = [] } = props.config;
    const addPage = operations.filter((item: any) => item.type == 'add')?.[0] as
      | {
        page?: string;
        name: string;
      }
      | undefined;
    if (!addPage || props.inbiz.browser.designer) {
      return;
    }
    const { operationflag, auth } = hasAuth(
      {
        table: props.config?.operations,
        //@ts-ignore
        auth: props.config.auth,
      },
      //@ts-ignore
      addPage.name,
      //@ts-ignore
      props.inbiz?.auth,
      'name',
    );
    return auth ? (
      <Button
        //@ts-ignore
        operationflag={operationflag}
        type="primary"
        style={{ padding: '4px 16px' }}
        icon={<PlusOutlined style={{ marginRight: '5px' }} />}
        onClick={() => {
          if (addPage && addPage.page) {
            const openOpt = {
              data: {},
              queryData: {
                [treeNodeParentId]: '0',
              },
              pageId: addPage.page?.split(',')[1],
              id: addPage.page?.split(',')[0],
            };
            modalRef?.current?.onOpen(openOpt, getMessage('Tree.addTo'));
          } else {
            message.warning(getMessage('tableView.tips.pleaseBindThePage'));
          }
        }}
      >
        <TextWidget>{changeString(addPage.name)}</TextWidget>
      </Button>
    ) : (
      <></>
    );
  }, [props.config, treeNodeParentId, modalRef, props.inbiz.browser.designer]);

  // 右键菜单
  const ContextMenu = useCallback(() => {
    return hasPerm ? (
      <Menu id={menuData.menuId} animation="">
        {menuData.items.map((item: any) => {
          const { operationflag, auth } = hasAuth(
            {
              table: props.config?.operations,
              //@ts-ignore
              auth: props.config.auth,
            },
            item.originName,
            //@ts-ignore
            props.inbiz?.auth,
            'name',
          );
          return (
            auth && (
              <Item
                title={getMessage(item.name)}
                key={item.key}
                id={item.key}
                //@ts-ignore
                operationflag={operationflag}
                onClick={(props) => {
                  if (treeData?.length) {
                    item.handler(props);
                  } else {
                    const { operations } = config;
                    const addPage = operations.filter((item: any) => item.type == 'add')?.[0] as {
                      page: string;
                    };
                    if (addPage && addPage.page) {
                      const openOpt = {
                        data: {},
                        queryData: {
                          [treeNodeParentId]: '0',
                        },
                        pageId: addPage.page?.split(',')[1],
                        id: addPage.page?.split(',')[0],
                      };
                      modalRef?.current?.onOpen(openOpt, getMessage('Tree.addTo'));
                    }
                  }
                }}
              >
                <TextWidget>{item.name}</TextWidget>
              </Item>
            )
          );
        })}
      </Menu>
    ) : null;
  }, [hasPerm, menuData, props.config?.operations]);

  // 右键显示菜单
  const handleContextMenu = (event: any, node: any) => {
    event.preventDefault();
    show(event, {
      props: node,
    });
  };

  const [modalWidth, modalHeight] = useMemo(() => {
    const {
      width: { widowWidth = 60, widthSuffix = '%' },
      height: { windowHeight = 60, heightSuffix = '%' },
    } = {
      width: props?.config?.formItems?.width || {},
      height: props?.config?.formItems?.height || {},
    };

    return [
      widthSuffix === '%' ? `${widowWidth}${widthSuffix}` : widowWidth,
      heightSuffix === '%' ? `${windowHeight}${heightSuffix}` : windowHeight,
    ];
  }, [props.config]);

  const onSearch = useCallback(async () => {
    if (!searchKey) return;
    if (sourcetype != 'model' && !configEvents?.current?.onSearch) {
      // 自定义数据源, 并且没有配置onSearch扩展代码时， 直接搜索本地数据
      if (treeListRef.current?.length) {
        const data = treeListRef.current
          .filter((item) => {
            if (item.title && typeof item.title === 'string') {
              return item.title.includes(searchKey);
            } else {
              return false;
            }
          })
          .map((item) => ({ [treeNameKey]: item.title, id: item.key }));
        $showSearch(true);
        $searchList(data as any);
      } else {
        $showSearch(true);
        $searchList([]);
      }
      return;
    }
    if (!configEvents?.current?.onSearch) {
      if (!sourceModel) {
        message.error(getMessage('Tree.dataSourceNotConfigured'));
        return;
      }
      if (!treeNameKey) {
        message.error(getMessage('Tree.displayFieldNotConfigured'));
        return;
      }
      let params = {
        sourceKey: sourceModel,
        sourceType: sourceTypeNum,
        id: -1, //搜索这里id随便传
        searchKey: treeNameKey,
        searchValue: searchKey,
      };
      const data = await getTreeDatas(appId, params);
      $showSearch(true);
      $searchList(data.Data);
    } else {
      const data = await configEvents.current.onSearch(treeNameKey, searchKey);
      $showSearch(true);
      $searchList(data);
    }
  }, [treeNameKey, searchKey, sourcetype]);

  const onSearchChange = useCallback((e) => {
    $searchKey(e.target.value);
  }, []);

  const handleCheck = useCallback(
    (checkedKeys, e) => {
      emit?.('onCheck', checkedKeys, e);
      setCheckedKeys(checkedKeys);
    },
    [setCheckedKeys],
  );

  // 对外暴露的方法
  useImperativeHandle(
    ref,
    () => ({
      ...api(configEvents, props, {
        treeDataRef,
        $treeData,
        checkStrictly,
        checkedKeys,
        treeNameKey,
        showTreeNameKey,
        treeNodeId,
        treeShowNodeId,
        treeNodeParentId,
        treeShowNodeParentId,
        setSelectNode,
        currentKey,
        $currentKey,
        setCheckedKeys,
        $expandedKeys,
        $checkedKeys,
        onRefresh
      }),
    }),
    [
      treeData,
      checkStrictly,
      checkedKeys,
      fieldRelation,
      currentKey,
      setSelectNode,
      setCheckedKeys,
    ],
  );
  const showTreeData = useMemo(() => {
    if (!showIcon) {
      return treeData;
    }
    return treeDataLevelFormat({
      treeData,
      format: (_, parents) => ({ _level: parents.length }),
    });
  }, [treeData, showIcon]);
  const InputIcon = useMemo(() => {
    return (
      !!searchIcon?.type && (
        <InbizIcon type={searchIcon?.type} style={{ color: searchIcon?.color }} />
      )
    );
  }, [searchIcon]);
  return (
    <div
      {...otherProps}
      style={{
        minWidth: minWidth,
        maxWidth: maxWidth,
        minHeight: minHeight,
        maxHeight: maxHeight,
        overflow: 'auto',
      }}
      className={`${prefixCls}-tree`}
    >
      {props.search ? (
        <div className="searchInput">
          <Input
            placeholder={props.searchPlaceholder}
            onPressEnter={onSearch}
            suffix={searchPosition == 'right' && InputIcon}
            prefix={searchPosition == 'left' && InputIcon}
            onChange={onSearchChange}
            allowClear
          />
        </div>
      ) : (
        ''
      )}
      {treeData?.length ? (
        <>
          {showSearch ? (
            <SearchList
              dataList={searchList}
              relationOpt={relationOpt}
              searchWord={searchKey}
              showKey={showTreeNameKey}
              checkable={checkable}
              setSelectAndExpand={(id?: string) => {
                if (id != undefined) {
                  setSelectNode(id as string);
                  $showSearch(false);
                }
              }}
            />
          ) : (
            <AntdTree
              className={prefixCls}
              rootClassName={viewMode == 'look' ? 'viewStyle' : ''}
              switcherIcon={
                <InbizIcon
                  type="icon-tree-down"
                  style={{
                    fontSize: 18,
                    color: '#aaa',
                    verticalAlign: 'text-bottom',
                    paddingTop: '3px',
                  }}
                />
              }
              showIcon={showIcon && !!IconsSettings?.config?.length}
              checkable={viewMode == 'look' ? false : checkable}
              checkStrictly={checkStrictly}
              selectable={viewMode == 'look' ? false : true}
              blockNode
              loadData={lazyLoadTreeData}
              onSelect={handleSelect}
              onRightClick={({ event, node }) => {
                emit?.('onRightClick');
                if (hasPerm) {
                  $currentKey([node.key]);
                  if (!readOnly && options.length || viewMode != 'look') {
                    handleContextMenu(event, node);
                  }
                }
              }}
              onCheck={handleCheck}
              expandedKeys={expandedKeys}
              onExpand={onExpand}
              selectedKeys={currentKey}
              treeData={showTreeData}
              icon={renderIcon}
              draggable={draggable ? { icon: false } : false}
              checkedKeys={checkedKeys}
              titleRender={configEvents.current?.onTitleRender || undefined}
              onDragStart={({ event, node }) => {
                emit?.('onDragStart', { event, node });
              }}
              onDragEnd={({ event, node }) => {
                emit?.('onDragEnd', { event, node });
              }}
              onDragEnter={({ event, node, expandedKeys }) => {
                emit?.('onDragEnter', { event, node, expandedKeys });
              }}
              onDragLeave={({ event, node }) => {
                emit?.('onDragLeave', { event, node });
              }}
              onDrop={({ event, node, dragNode, dragNodesKeys }) => {
                emit?.('onDrop', { event, node, dragNode, dragNodesKeys });
              }}
              onDragOver={({ event, node }) => {
                emit?.('onDragOver', { event, node });
              }}
            />
          )}

          <RenderModal
            ref={modalRef}
            inbiz={props.inbiz}
            callBackEvents={configEvents}
            emit={modalEmit}
            style={{ height: modalHeight }}
            width={modalWidth}
          />
          {!props.inbiz.browser.designer && operations?.length ? <ContextMenu /> : null}
        </>
      ) : sourceModel && loading ? null : (
        <>
          <Empty
            image={Empty.PRESENTED_IMAGE_SIMPLE}
            description={<TextWidget>pageselect.no_data</TextWidget>}
          />
          {!props.inbiz.browser.designer &&
            operations?.filter((item: any) => item.type == 'add').length ? (
            <div style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
              {addButton}
              <RenderModal
                ref={modalRef}
                inbiz={props.inbiz}
                callBackEvents={configEvents}
                emit={modalEmit}
                style={{ height: modalHeight }}
                width={modalWidth}
              />
            </div>
          ) : null}
        </>
      )}
    </div>
  );
});

export default Tree;
